﻿namespace QuickMail.BusinessLogic
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Windows;

    using QuickMail.DataModels;
    using QuickMail.ViewModels;

    class EnvironmentWorker
    {
        public bool ResultScanDirs;
        
        /// <summary>
        /// Recursively scans directories and creates a tree of rules.
        /// </summary>
        public bool RecursiveCreateRules(string parentPath, RuleVm parentFolder)
        {
            try
            {
                if (!ResultScanDirs) 
                    return false;

                foreach (var directory in Directory.GetDirectories(parentPath))
                {
                    var childFolder = new RuleVm
                    {
                        Title = Path.GetFileName(directory),
                        DirectoryPath = directory
                    };

                    parentFolder.Childrens.Add(childFolder);
                    ResultScanDirs = RecursiveCreateRules(directory, childFolder);
                }
                return ResultScanDirs;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                StaticFields.Logger.Warn(" -- {0}.{1} -- {2}", GetType().FullName,
                    System.Reflection.MethodBase.GetCurrentMethod().Name, ex.Message);
                return ResultScanDirs = false;
            }
        }

        /// <summary>
        /// Calculates the total size of files to be sent.
        /// </summary>
        /// <param name="filePaths">Paths to files</param>
        /// <returns>The total size of the files.</returns>
        public static long GetDirectorySize(IEnumerable<string> filePaths)
        {
            return filePaths.Select(filePath => new FileInfo(filePath)).Select(info => info.Length).Sum();
        }

        /// <summary>
        /// Selects only the appropriate files.
        /// </summary>
        /// <param name="ruleVm">Rule for checking</param>
        /// <returns>File paths</returns>
        public static string[] GetFiles(RuleVm ruleVm)
        {
            string[] filePaths = Directory.GetFiles(ruleVm.DirectoryPath);

            if (filePaths.Any(filePath => Path.GetExtension(filePath) == ".lnk"))
            {
                StaticFields.Logger.Warn(" -- {0}.{1} -- {2}", typeof(EnvironmentWorker).FullName,
                    System.Reflection.MethodBase.GetCurrentMethod().Name, "You can not send the labels in the mail.");

                RemoveFiles(filePaths.Where(filePath => Path.GetExtension(filePath) == ".lnk"));
                filePaths = Directory.GetFiles(ruleVm.DirectoryPath);
            }

            if (ruleVm.FilesTypeList == null || !ruleVm.FilesTypeList.Any())
            {
                return filePaths;
            }
            //else
            {
                return filePaths.Where(file => ruleVm.FilesTypeList.Any(ft => file.Contains(ft.Replace("*", "")))).ToArray();
            }
        }

        /// <summary>
        /// Checks access to all files in the folder.
        /// </summary>
        public static bool IsFilesReady(IEnumerable<string> filePaths)
        {
            return filePaths.All(filePath => !IsFileLocked(filePath));
        }

        /// <summary>
        /// Check access to the file.
        /// </summary>
        private static bool IsFileLocked(string filePath)
        {
            try
            {
                using (File.Open(filePath, FileMode.Open)) { }
            }
            catch (IOException ex)
            {
                StaticFields.Logger.Warn(" -- {0}.{1} -- {2}", typeof(EnvironmentWorker).FullName,
                    System.Reflection.MethodBase.GetCurrentMethod().Name, ex.Message);
                int errorCode = Marshal.GetHRForException(ex) & ((1 << 16) - 1);
                return errorCode == 32 || errorCode == 33;
            }

            return false;
        }

        /// <summary>
        /// Removes files that can not be sent by mail. 
        /// For example, the labels.
        /// </summary>
        private static void RemoveFiles(IEnumerable<string> filePaths)
        {
            foreach (var file in filePaths)
            {
                try
                {
                    File.Delete(file);
                }
                catch (Exception ex)
                {
                    StaticFields.Logger.Warn(" -- {0}.{1} -- {2}", typeof(EnvironmentWorker).FullName,
                        System.Reflection.MethodBase.GetCurrentMethod().Name, ex.Message
                        + "\nFailed to delete file: " + file);
                }
            }
        }

        public static void MoveFiles(IEnumerable<string> filePaths, string destPath)
        {
            if (!Directory.Exists(destPath)) 
                Directory.CreateDirectory(destPath);

            foreach (var filePath in filePaths)
            {
                File.Move(filePath, destPath + Path.GetFileName(filePath));
            }
        }

        public static void CopyFiles(IEnumerable<string> filePaths, string destPath)
        {
            if (!Directory.Exists(destPath))
                Directory.CreateDirectory(destPath);

            foreach (var filePath in filePaths)
            {
                File.Copy(filePath, destPath + Path.GetFileName(filePath));
            }
        }
    }
}
